#include <sxBezierCurve.h>
#include <sxDistances.h>

const static Eigen::Vector3f DEFAULT_END_POINT_PRIMARY = Eigen::Vector3f(1.0f, 0.0f, 0.0f);
const static Eigen::Vector3f DEFAULT_END_POINT_SECONDARY = Eigen::Vector3f(2.0f, 0.0f, 0.0f);
const static Eigen::Vector3f DEFAULT_CONTROL_POINT_PRIMARY = Eigen::Vector3f(0.0f, 0.0f, 0.0f);
const static Eigen::Vector3f DEFAULT_CONTROL_POINT_SECONDARY = Eigen::Vector3f(3.0f, 0.0f, 0.0f);

Sx::Graphics::Objects::BezierCurve::BezierCurve() : GraphicsObject() {
	this->initialize();
}

Sx::Graphics::Objects::BezierCurve::BezierCurve(const Eigen::Vector3f& endPoint_0, const Eigen::Vector3f& endPoint_1) {
	this->initialize();
	Math::LineFromParametric(endPoint_0, endPoint_0.normalized(), 1.0f, this->endPoint_0.position(), this->controlPoint_0.position());
	Math::LineFromParametric(endPoint_1, endPoint_1.normalized(), 1.0f, this->endPoint_1.position(), this->controlPoint_1.position());

	if ( endPoint_0 == Eigen::Vector3f::Zero() ) this->controlPoint_0.position() = Eigen::Vector3f(-1.0f, 0.0f, 0.0f);
	if ( endPoint_1 == Eigen::Vector3f::Zero() ) this->controlPoint_1.position() = Eigen::Vector3f(1.0f, 0.0f, 0.0f);

	if ( this->endPoint_0.position() == this->endPoint_1.position() ) this->endPoint_1.position().x() += 1.0f;
	if ( this->controlPoint_0.position() == this->controlPoint_1.position() ) this->controlPoint_1.position().x() += 1.0f;
}

Sx::Graphics::Objects::BezierCurve::BezierCurve(const Eigen::Vector3f& endPoint_0, const Eigen::Vector3f& endPoint_1, const Eigen::Vector3f& controlPoint_0, const Eigen::Vector3f& controlPoint_1) {
	this->initialize();
	this->endPoint_0.position() = endPoint_0;
	this->endPoint_1.position() = endPoint_1;
	this->controlPoint_0.position() = controlPoint_0;
	this->controlPoint_1.position() = controlPoint_1;
}

void Sx::Graphics::Objects::BezierCurve::initialize() {
	this->endPoint_0.position() = DEFAULT_END_POINT_PRIMARY;
	this->endPoint_1.position() = DEFAULT_END_POINT_SECONDARY;
	this->controlPoint_0.position() = DEFAULT_CONTROL_POINT_PRIMARY;
	this->controlPoint_1.position() = DEFAULT_CONTROL_POINT_SECONDARY;
}

Sx::Graphics::Objects::BezierCurve::~BezierCurve() {}

bool Sx::Graphics::Objects::BezierCurve::construct() { return true; }
void Sx::Graphics::Objects::BezierCurve::update(float dt) { return; }

void Sx::Graphics::Objects::BezierCurve::setLine(const Eigen::Vector3f& endPoint_0, const Eigen::Vector3f& endPoint_1) {
	Math::LineFromParametric(endPoint_0, endPoint_0.normalized(), 1.0f, this->endPoint_0.position(), this->controlPoint_0.position());
	Math::LineFromParametric(endPoint_1, endPoint_1.normalized(), 1.0f, this->endPoint_1.position(), this->controlPoint_1.position());
}

void Sx::Graphics::Objects::BezierCurve::setCurve(const Eigen::Vector3f& endPoint_0, const Eigen::Vector3f& endPoint_1, const Eigen::Vector3f& controlPoint_0, const Eigen::Vector3f& controlPoint_1) {
	this->endPoint_0.position() = endPoint_0;
	this->endPoint_1.position() = endPoint_1;
	this->controlPoint_0.position() = controlPoint_0;
	this->controlPoint_1.position() = controlPoint_1;
}

void Sx::Graphics::Objects::BezierCurve::setEndPoint(bool index, const Eigen::Vector3f& point) {
	if ( index == false ) this->endPoint_0.position() = point;
	else this->endPoint_1.position() = point;
}

void Sx::Graphics::Objects::BezierCurve::setEndPointPrimary(const Eigen::Vector3f& point) {
	this->endPoint_0.position() = point;
}

void Sx::Graphics::Objects::BezierCurve::setEndPointSecondary(const Eigen::Vector3f& point) {
	this->endPoint_1.position() = point;
}

void Sx::Graphics::Objects::BezierCurve::setEndPoints(const Eigen::Vector3f& endPoint_0, const Eigen::Vector3f& endPoint_1) {
	this->endPoint_0.position() = endPoint_0;
	this->endPoint_1.position() = endPoint_1;
}

void Sx::Graphics::Objects::BezierCurve::setControlPoint(bool index, const Eigen::Vector3f& controlPoint) {
	if ( index == false ) this->controlPoint_0.position() = controlPoint;
	else this->controlPoint_1.position() = controlPoint;
}

void Sx::Graphics::Objects::BezierCurve::setControlPointPrimary(const Eigen::Vector3f& controlPoint) {
	this->controlPoint_0.position() = controlPoint;
}

void Sx::Graphics::Objects::BezierCurve::setControlPointSecondary(const Eigen::Vector3f& controlPoint) {
	this->controlPoint_1.position() = controlPoint;
}

void Sx::Graphics::Objects::BezierCurve::setControlPoints(const Eigen::Vector3f& controlPoint_0, const Eigen::Vector3f& controlPoint_1) {
	this->controlPoint_0.position() = controlPoint_0;
	this->controlPoint_1.position() = controlPoint_1;
}

void Sx::Graphics::Objects::BezierCurve::setEndPointSelected(bool index, bool selected) {
	if ( index == 0 ) this->endPoint_0.setSelected(selected);
	else this->endPoint_1.setSelected(selected);
}

void Sx::Graphics::Objects::BezierCurve::setControlPointSelected(bool index, bool selected) {
	if ( index == 0 ) this->controlPoint_0.setSelected(selected);
	else this->controlPoint_1.setSelected(selected);
}

void Sx::Graphics::Objects::BezierCurve::setSelected(bool ep0, bool ep1, bool cp0, bool cp1) {
	this->endPoint_0.setSelected(ep0);
	this->endPoint_1.setSelected(ep1);
	this->controlPoint_0.setSelected(cp0);
	this->controlPoint_1.setSelected(cp1);
}

bool Sx::Graphics::Objects::BezierCurve::isEndPointSelected(bool index) const {
	if ( index == 0 ) return this->endPoint_0.isSelected();
	else return this->endPoint_1.isSelected();
}

bool Sx::Graphics::Objects::BezierCurve::isControlPointSelected(bool index) const {
	if ( index == 0 ) return this->controlPoint_0.isSelected();
	else return this->controlPoint_1.isSelected();
}

void Sx::Graphics::Objects::BezierCurve::select() {
	this->selected = true;
	this->endPoint_0.select();
	this->endPoint_1.select();
	this->controlPoint_0.select();
	this->controlPoint_1.select();
}

void Sx::Graphics::Objects::BezierCurve::deselect() {
	this->selected = false;
	this->endPoint_0.deselect();
	this->endPoint_1.deselect();
	this->controlPoint_0.deselect();
	this->controlPoint_1.deselect();
}

void Sx::Graphics::Objects::BezierCurve::setOneToOneFunction(bool b) {
	this->oneToOneFunction = b;
}

void Sx::Graphics::Objects::BezierCurve::setHasLoop(bool b) {
	this->looped = b;
}

bool Sx::Graphics::Objects::BezierCurve::isOneToOneFunction() const {
	return this->oneToOneFunction;
}

bool Sx::Graphics::Objects::BezierCurve::hasLoop() const {
	return this->looped;
}

Sx::Graphics::Objects::Point& Sx::Graphics::Objects::BezierCurve::endPoint(bool index) {
	if ( index == false ) return this->endPoint_0;
	else return this->endPoint_1;
}

Sx::Graphics::Objects::Point& Sx::Graphics::Objects::BezierCurve::endPointPrimary() {
	return this->endPoint_0;
}

Sx::Graphics::Objects::Point& Sx::Graphics::Objects::BezierCurve::endPointSecondary() {
	return this->endPoint_1;
}

const Sx::Graphics::Objects::Point& Sx::Graphics::Objects::BezierCurve::getEndPoint(bool index) const {
	if ( index == false ) return this->endPoint_0;
	else return this->endPoint_1;
}

const Sx::Graphics::Objects::Point& Sx::Graphics::Objects::BezierCurve::getEndPointPrimary() const {
	return this->endPoint_0;
}

const Sx::Graphics::Objects::Point& Sx::Graphics::Objects::BezierCurve::getEndPointSecondary() const {
	return this->endPoint_1;
}

Sx::Graphics::Objects::Point& Sx::Graphics::Objects::BezierCurve::controlPoint(bool index) {
	if ( index == false ) return this->controlPoint_0;
	else return this->controlPoint_1;
}

Sx::Graphics::Objects::Point& Sx::Graphics::Objects::BezierCurve::controlPointPrimary() {
	return this->controlPoint_0;
}

Sx::Graphics::Objects::Point& Sx::Graphics::Objects::BezierCurve::controlPointSecondary() {
	return this->controlPoint_1;
}

const Sx::Graphics::Objects::Point& Sx::Graphics::Objects::BezierCurve::getControlPoint(bool index) const {
	if ( index == false ) return this->controlPoint_0;
	else return this->controlPoint_1;
}

const Sx::Graphics::Objects::Point& Sx::Graphics::Objects::BezierCurve::getControlPointPrimary() const {
	return this->controlPoint_0;
}

const Sx::Graphics::Objects::Point& Sx::Graphics::Objects::BezierCurve::getControlPointSecondary() const {
	return this->controlPoint_1;
}

